﻿using System;
using System.Security.Cryptography;
using System.Text;

namespace LuYao.Toolkit.DEncrypt
{
    /// <summary>
    /// AES加密
    /// </summary>
    public static class AESHelper
    {
        /// <summary>
        /// AES加密
        /// </summary>
        /// <param name="source"></param>
        /// <param name="key">密钥</param>
        /// <param name="iv">初始向量</param>
        /// <param name="padding">填充模式</param>
        /// <param name="mode">加密模式</param>
        /// <returns></returns>
        public static (bool isOk, string text) AESEncrypt(this string source, string key, string iv = "", PaddingMode padding = PaddingMode.PKCS7, CipherMode mode = CipherMode.CBC)
        {
            try
            {
                byte[] keyBytes = Encoding.UTF8.GetBytes(key);
                byte[] textBytes = Encoding.UTF8.GetBytes(source);
                byte[] ivBytes = Encoding.UTF8.GetBytes(iv);

                byte[] useKeyBytes = new byte[16];
                byte[] useIvBytes = new byte[16];

                if (keyBytes.Length > useKeyBytes.Length)
                    Array.Copy(keyBytes, useKeyBytes, useKeyBytes.Length);
                else
                    Array.Copy(keyBytes, useKeyBytes, keyBytes.Length);

                if (ivBytes.Length > useIvBytes.Length)
                    Array.Copy(ivBytes, useIvBytes, useIvBytes.Length);
                else
                    Array.Copy(ivBytes, useIvBytes, ivBytes.Length);

                Aes aes = System.Security.Cryptography.Aes.Create();
                aes.KeySize = 256;//秘钥的大小，以位为单位,128,256等
                aes.BlockSize = 128;//支持的块大小
                aes.Padding = padding;//填充模式
                aes.Mode = mode;
                aes.Key = useKeyBytes;
                aes.IV = useIvBytes;//初始化向量，如果没有设置默认的16个0

                ICryptoTransform cryptoTransform = aes.CreateEncryptor();
                byte[] resultBytes = cryptoTransform.TransformFinalBlock(textBytes, 0, textBytes.Length);

                return (true, Convert.ToBase64String(resultBytes));
            }
            catch (Exception ex)
            {
                return (false, ex.Message);
            }
        }

        /// <summary>
        /// AES解密
        /// </summary>
        /// <param name="source"></param>
        /// <param name="key">密钥</param>
        /// <param name="iv">初始向量</param>
        /// <param name="padding">填充模式</param>
        /// <param name="mode">加密模式</param>
        /// <param name="sourceIsHex">待解密字符串编码是否需要Hex编码</param>
        /// <returns></returns>
        public static (bool isOk, string text) AESDecrypt(this string source, string key, string iv = "", PaddingMode padding = PaddingMode.PKCS7, CipherMode mode = CipherMode.CBC, bool sourceIsHex = false)
        {
            try
            {
                byte[] keyBytes = Encoding.UTF8.GetBytes(key);
                byte[] textBytes = sourceIsHex ? HexStringToByteArray(source) : Convert.FromBase64String(source);
                byte[] ivBytes = Encoding.UTF8.GetBytes(iv);

                byte[] useKeyBytes = new byte[16];
                byte[] useIvBytes = new byte[16];

                if (keyBytes.Length > useKeyBytes.Length)
                    Array.Copy(keyBytes, useKeyBytes, useKeyBytes.Length);
                else
                    Array.Copy(keyBytes, useKeyBytes, keyBytes.Length);

                if (ivBytes.Length > useIvBytes.Length)
                    Array.Copy(ivBytes, useIvBytes, useIvBytes.Length);
                else
                    Array.Copy(ivBytes, useIvBytes, ivBytes.Length);

                Aes aes = System.Security.Cryptography.Aes.Create();
                aes.KeySize = 128;//秘钥的大小，以位为单位,128,256等
                aes.BlockSize = 128;//支持的块大小
                aes.Padding = padding;//填充模式
                aes.Mode = mode;
                aes.Key = useKeyBytes;
                aes.IV = useIvBytes;//初始化向量，如果没有设置默认的16个0

                ICryptoTransform decryptoTransform = aes.CreateDecryptor();
                byte[] resultBytes = decryptoTransform.TransformFinalBlock(textBytes, 0, textBytes.Length);

                return (true, Encoding.UTF8.GetString(resultBytes));
            }
            catch (Exception ex)
            {
                return (false, ex.Message);
            }
        }
        /// <summary>
        /// 将指定的16进制字符串转换为byte数组
        /// </summary>
        /// <param name="s">16进制字符串(如：“7F 2C 4A”或“7F2C4A”都可以)</param>
        /// <returns>16进制字符串对应的byte数组</returns>
        public static byte[] HexStringToByteArray(string s)
        {
            s = s.Replace(" ", "");
            byte[] buffer = new byte[s.Length / 2];
            for (int i = 0; i < s.Length; i += 2)
                buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16);
            return buffer;
        }

        /// <summary>
        /// 将一个byte数组转换成一个格式化的16进制字符串
        /// </summary>
        /// <param name="data">byte数组</param>
        /// <returns>格式化的16进制字符串</returns>
        public static string ByteArrayToHexString(byte[] data)
        {
            StringBuilder sb = new StringBuilder(data.Length * 3);
            foreach (byte b in data)
            {
                //16进制数字
                sb.Append(Convert.ToString(b, 16).PadLeft(2, '0'));
                //16进制数字之间以空格隔开
                //sb.Append(Convert.ToString(b, 16).PadLeft(2, '0').PadRight(3, ' '));
            }
            return sb.ToString().ToUpper();
        }
    }

}
